package com.yfux.cling_player.ui;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.SeekBar;
import android.widget.Toast;
import android.widget.VideoView;

import androidx.appcompat.app.AppCompatActivity;

import com.yfux.cling_player.R;
import com.yfux.cling_player.databinding.ActivityVideoPlayerBinding;
import com.yfux.cling_player.nums.RenderState;
import com.yfux.cling_player.parcelables.CastAction;
import com.yfux.cling_player.service.DLNARendererService;
import com.yfux.cling_player.service.controller.RenderControl;
import com.yfux.cling_player.util.LogUtil;

public class VideoPlayerActivity extends AppCompatActivity {
    final String keyExtraCastAction = "extra.castAction";
    protected DLNARendererService rendererService;
    protected CastAction castAction;
    private String nextURI;
    private ActivityVideoPlayerBinding binding;
    private RenderState renderState = RenderState.IDLE;
    private LogUtil logger = new LogUtil("VideoPlayerActivity");
    private Handler handler = new Handler(Looper.getMainLooper());
    private static final int PROGRESS_POST_DELAY = 10;
    private static final int HIDE_PANEL_DELAY = 2000;
    private static final int SEEK_DELAY = 100;
    private static final int SEEK_TIME_INTERVAL = 5000;
    /**
     * 正在长按的键值
     */
    private int longPressKey = 0;
    private Runnable seekLeftRunnable = new Runnable() {
        @Override
        public void run() {
            seekLeft();
            handler.postDelayed(this, SEEK_DELAY);
        }
    };
    private Runnable seekRightRunnable = new Runnable() {
        @Override
        public void run() {
            seekRight();
            handler.postDelayed(this, SEEK_DELAY);
        }
    };
    // 定义 Runnable 来更新进度
    private Runnable updateProgressRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                if (binding.videoView.isPlaying()) {
                    // 单位是ms
                    int currentPosition = binding.videoView.getCurrentPosition();
                    int duration = binding.videoView.getDuration();
                    int progress = currentPosition * 100 / (duration - PROGRESS_POST_DELAY);
                    progress = progress < 0 ? 0 : progress > 100 ? 100 : progress;
                    binding.progressBar.setProgress(progress);
                    binding.curTimeView.setText(getTimeStr(currentPosition));
//                logger.i("currentPosition = " + currentPosition
//                        + ", duration = " + duration
//                        + ", progress = " + progress);
                    handler.postDelayed(this, PROGRESS_POST_DELAY);
                }
            } catch (IllegalStateException e) {
            }
        }

    };
    private Runnable hideControllerPanelRunnable = () -> {
        binding.controlPanel.setVisibility(View.GONE);
    };


    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            setRendererService(service);
            VideoPlayerActivity.this.onServiceConnected();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            rendererService = null;
        }
    };

    private boolean isNullOrBlank(String s) {
        return s == null ? true : s.isEmpty();
    }

    public void setRenderState(RenderState value) {
        if (renderState != value) {
            renderState = value;
            if (rendererService != null) {
                rendererService.notifyAvTransportLastChange(renderState);
            }
        }
    }

    public void onServiceConnected() {
        if (rendererService != null) {
            rendererService.bindRealPlayer(new VideoRenderControl(binding.videoView));
        }
        openMedia();
    }

    private String getTimeStr(int duration) {
        int hour = duration / 1000 / 3600;
        int minute = duration / 1000 / 60 % 60;
        int second = duration / 1000 % 60;
        return String.format("%02d:%02d:%02d", hour, minute, second);
    }

    private void showControllerPanel() {
        handler.removeCallbacks(hideControllerPanelRunnable);
        binding.controlPanel.setVisibility(View.VISIBLE);
        handler.postDelayed(hideControllerPanelRunnable, HIDE_PANEL_DELAY);
    }

    private void startLoading() {
        binding.loadingLayout.setVisibility(View.VISIBLE);
        // 创建旋转动画
        RotateAnimation rotate = new RotateAnimation(
                0, 360,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(2000); // 设置持续时间为 1 秒
        rotate.setInterpolator(new LinearInterpolator()); // 设置插值器为线性插值器
        rotate.setRepeatCount(Animation.INFINITE); // 设置动画无限重复

        // 应用动画
        binding.loadingImageView.setAnimation(rotate);
    }

    private void finishLoading() {
        binding.loadingImageView.clearAnimation();
        binding.loadingLayout.setVisibility(View.GONE);
    }

    private void initViews() {
        handler.postDelayed(hideControllerPanelRunnable, HIDE_PANEL_DELAY);
        binding.btn.setOnClickListener((btn) -> {
            boolean tag = (Boolean) btn.getTag();
            if (tag) pauseVideo();
            else playVideo();
        });
        binding.progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            private int startProgress;

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                startProgress = seekBar.getProgress();
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                int endProgress = seekBar.getProgress();
                int deltaProgress = endProgress - startProgress;
                if (binding.videoView.isPlaying()) {
                    int duration = binding.videoView.getDuration();
                    int deltaPos = deltaProgress * (duration - PROGRESS_POST_DELAY);
                    deltaPos = deltaPos < 0 ? 0 : deltaPos > duration ? duration : deltaPos;
//                logger.i("进度改变值: " + deltaPos + "ms");
                    binding.videoView.seekTo(binding.videoView.getCurrentPosition() + deltaPos);
                }
            }
        });
        binding.getRoot().setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                showControllerPanel();
                return true;
            }
        });

        if (binding.videoView.isPlaying()) {
            binding.videoView.pause();
            setRenderState(RenderState.PAUSED);
        }

        binding.videoView.setOnPreparedListener(mp -> {
            playVideo();
            int duration = binding.videoView.getDuration();
            binding.totalTimeView.setText(getTimeStr(duration));
            finishLoading();
        });

        binding.videoView.setOnErrorListener((mp, what, extra) -> {
            setRenderState(RenderState.ERROR);
            if (nextURI == null || nextURI.isEmpty()) {
                Toast.makeText(this,
                        "投屏启动失败", Toast.LENGTH_SHORT).show();
            } else {
                startLoading();
                binding.videoView.setVideoURI(Uri.parse(nextURI));
                nextURI = null;
            }
            return true;
        });

        binding.videoView.setOnCompletionListener(mp -> {
            setRenderState(RenderState.STOPPED);
            if (nextURI == null || nextURI.isEmpty()) {
                finish();
            } else {
                startLoading();
                binding.videoView.setVideoURI(Uri.parse(nextURI));
                nextURI = null;
            }
        });
    }

    private void hideSystemBars() {
        // Set full screen flags
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_FULLSCREEN |
                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
        );
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        logger.i("onCreate, castAction = " + castAction);
        super.onCreate(savedInstanceState);
        binding = ActivityVideoPlayerBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        hideSystemBars();
        initViews();

        ///////////////////////////////////////////////////////////////////////////////////////
        castAction = getIntent().getParcelableExtra(keyExtraCastAction);
        if (castAction != null && !isNullOrBlank(castAction.getStop())) {
            finish();
            return;
        }

        bindService(new Intent(this, DLNARendererService.class),
                serviceConnection, Context.BIND_AUTO_CREATE);

        ///////////////////////////////////////////////////////////////////////////////////////
    }

    @Override
    protected void onNewIntent(Intent newIntent) {
        super.onNewIntent(newIntent);
        setIntent(newIntent);
        if (castAction != null && !isNullOrBlank(castAction.getStop())) {
            finish();
            return;
        }
        openMedia();
    }

    @SuppressLint("SetTextI18n")
    private void openMedia() {
        if (castAction != null) {
            String currentURI = castAction.getCurrentURI();
            if (currentURI != null) {
                startLoading();
                binding.videoView.setVideoURI(Uri.parse(currentURI));
            }
            String nextURI = castAction.getNextURI();
            if (nextURI != null) {
                this.nextURI = nextURI;
            }
            if (castAction.getStop() != null) {
                finish();
            }
        }
    }

    private void setRendererService(IBinder service) {
        logger.i("setRendererService");
        rendererService = ((DLNARendererService.RendererServiceBinder) service).getService();
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        setRenderState(RenderState.STOPPED);
        stopVideo();
        unbindService(serviceConnection);
        if (rendererService != null) {
            rendererService.bindRealPlayer(null);
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        showControllerPanel();
        boolean handled = super.onKeyDown(keyCode, event);
        if (rendererService != null) {
            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||   // 音量键
                    keyCode == KeyEvent.KEYCODE_VOLUME_UP ||  // 音量减
                    keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {  // 静音
                AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
                if (audioManager != null) {
                    int volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                    rendererService.notifyRenderControlLastChange(volume);
                }
            } else if (keyCode == KeyEvent.KEYCODE_ENTER // 回车键
                    || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // OK键
                if (binding.videoView.isPlaying()) {
                    pauseVideo();
                } else {
                    playVideo();
                }
            } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
//                if (longPressKey != KeyEvent.KEYCODE_DPAD_LEFT) seekLeft();
                handler.post(seekLeftRunnable);
            } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
//                if (longPressKey != KeyEvent.KEYCODE_DPAD_RIGHT) seekRight();
                handler.post(seekRightRunnable);
            }
        }
        return handled;
    }

//    @Override
//    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
//        boolean handled = super.onKeyDown(keyCode, event);
//        if (rendererService != null) {
//            if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
//                longPressKey = KeyEvent.KEYCODE_DPAD_LEFT;
//                handler.post(seekLeftRunnable);
//            } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
//                longPressKey = KeyEvent.KEYCODE_DPAD_RIGHT;
//                handler.post(seekRightRunnable);
//            }
//        }
//        return handled;
//    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        boolean handled = super.onKeyUp(keyCode, event);
        if (rendererService != null) {
            if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
                handler.removeCallbacks(seekLeftRunnable);
//                longPressKey = 0;
            } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
                handler.removeCallbacks(seekRightRunnable);
//                longPressKey = 0;
            }
        }
        return handled;
    }

    private void seekLeft() {
        if (rendererService != null && binding.videoView.isPlaying()) {
            int currentPosition = binding.videoView.getCurrentPosition();
            int newPosition = currentPosition - SEEK_TIME_INTERVAL;
            newPosition = newPosition < 0 ? 0 : newPosition;
            binding.videoView.seekTo(newPosition);
        }
    }

    private void seekRight() {
        if (rendererService != null && binding.videoView.isPlaying()) {
            int currentPosition = binding.videoView.getCurrentPosition();
            int duration = binding.videoView.getDuration();
            int newPosition = currentPosition + SEEK_TIME_INTERVAL;
            newPosition = newPosition > duration ? duration : newPosition;
            binding.videoView.seekTo(newPosition);
        }
    }

    private Drawable getDrawableFix(int resId) {
        Drawable drawable;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            drawable = this.getResources().getDrawable(resId, this.getTheme());
        } else {
            drawable = this.getResources().getDrawable(resId);
        }
        return drawable;
    }

    private void playVideo() {
        binding.btn.setTag(true);
        binding.videoView.start();
        setRenderState(RenderState.PLAYING);
        binding.btn.setImageDrawable(getDrawableFix(R.drawable.pause));
        binding.progressBar.setProgress(binding.videoView.getCurrentPosition() * 100 / (binding.videoView.getDuration() - 1000));
        handler.post(updateProgressRunnable);
    }

    private void pauseVideo() {
        binding.btn.setTag(false);
        binding.videoView.pause();
        setRenderState(RenderState.PAUSED);
        binding.btn.setImageDrawable(getDrawableFix(R.drawable.play));
        handler.removeCallbacks(updateProgressRunnable);
    }

    private void stopVideo() {
        binding.videoView.stopPlayback();
        binding.btn.setTag(false);
        binding.btn.setImageDrawable(getDrawableFix(R.drawable.play));
        handler.removeCallbacks(updateProgressRunnable);
    }

    private class VideoRenderControl extends RenderControl {
        private final VideoView videoView;

        public VideoRenderControl(VideoView videoView) {
            this.videoView = videoView;
        }

        @Override
        public long getCurrentPosition() {
            return (long) videoView.getCurrentPosition();
        }

        @Override
        public long getDuration() {
            return (long) videoView.getDuration();
        }

        @Override
        public void play(Double speed) {
            playVideo();
            setRenderState(RenderState.PLAYING);
        }

        @Override
        public void pause() {
            pauseVideo();
            setRenderState(RenderState.PAUSED);
        }

        @Override
        public void seek(long millSeconds) {
            videoView.seekTo((int) millSeconds);
        }

        @Override
        public void stop() {
            videoView.stopPlayback();
            setRenderState(RenderState.STOPPED);
            finish();
        }

        @Override
        public RenderState getState() {
            return renderState;
        }
    }
}